use std::{sync::{mpsc, Arc, Mutex},thread};

// 1.创建ThreadPool线程池的crate
// 分配空间存储线程
pub struct ThreadPool{
    // threads: Vec<thread::JoinHandle<()>>,
    workers: Vec<Worker>,
    sender: Option<mpsc::Sender<Job>>, //3.增加信道多生产单消费,10.增加Option是向线程发送信号使其停止接收任务
}
// struct Job;
// 8.为存放每个闭包的Box创建一个Job类型别名,接着信道中发出
type Job = Box<dyn FnOnce() + Send + 'static>;
impl ThreadPool {
    /// Create a new ThreadPool
    /// The size is the of threads in the pool
    ///
    /// #Panics
    /// The `new` function will panic if the size is zero
    pub fn new(size: usize) -> ThreadPool {
        assert!(size > 0);
        // 获取CPU内核数量
        let cpu_core_num = thread::available_parallelism().unwrap().get();
        // println!("{} cpu cores", cpu_core_num);
        // 通过cpu内核数量限制分配空间最大值
        let thread_num;
        if size > cpu_core_num {
            thread_num = cpu_core_num;
        } else {
            thread_num = size;
        }
        // let mut threads = Vec::with_capacity(size);
        let mut workers = Vec::with_capacity(thread_num);
        // println!("{} new size", thread_num);

        // 3.创建信道
        let (sender, receiver) = mpsc::channel();
        // 5.将信道的接收端传递给worker
        let receiver = Arc::new(Mutex::new(receiver));
        for id in 0..size {
            // create some threads and store them in the vector
            workers.push(Worker::new(id, Arc::clone(&receiver)));
        }

        // ThreadPool { threads }
        ThreadPool { workers, sender: Some(sender) }
    }
    // 参考thread::spawn方法实现execute方法
    // pub fn spawn<F, T>(f: F) -> JoinHandle<T>
    // where
    //     F: FnOnce() -> T + Send + 'static,
    //     T: Send + 'static
    pub fn execute<F>(&self, f: F)
    where F: FnOnce() + Send + 'static,{
        // 6.实现execute方法
        let job = Box::new(f);
        self.sender.as_ref().unwrap().send(job).unwrap(); //10.向线程发送信号使其停止接收任务
    }
}
// 9.为ThreadPool实现Drop trait 实现优雅停机与清理
impl Drop for ThreadPool{
    fn drop(&mut self) {
        drop(self.sender.take().unwrap());
        for worker in &mut self.workers {
            println!("Shutting down worker {}", worker.id);
            if let Some(thread) = worker.thread.take() {
                thread.join().unwrap();
            }
        }
    }
}
// 2.Worker结构体负责从ThreadPool中将代码传递给线程
// 定义worker结构体存放id和JoinHandle<()>
struct Worker{
    id: usize,
    // thread: thread::JoinHandle<()>,
    thread: Option<thread::JoinHandle<()>>, //9.增加option实现join的可拿走所有权
}
impl Worker{
    // 4.修改ThreadPool来储存一个传输Job实例的发送者
    fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
        // let thread = thread::spawn(|| {
        //     receiver;
        // });
        // 8.为存放每个闭包的Box创建一个Job类型别名,接着信道中发出
        // let thread = thread::spawn(move || loop {
        //     let job = receiver.lock().unwrap().recv().unwrap();
        //     println!("Worker {id} got a job; executing.");
        //     job();
        // });
        // 10.在join worker线程之前显式丢弃sender
        let thread = thread::spawn(move|| loop {
           let message = receiver.lock().unwrap().recv();
            match message {
                Ok(job) => {
                    println!("Worker {} got a job; executing.", id);
                    job();
                },
                Err(_) => {
                    println!("Worker {} disconnected; shutting down.", id);
                    break;
                }
            }
        });
        Worker{id, thread:Some(thread)}
    }
}